﻿using Castle.MicroKernel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WJP.Dependency
{
    /// <summary>
    /// 此类用于将批处理解析的作用域封装在一个<c>using</c>语句中
    /// <para>它继承了<see cref="IDisposable" />和<see cref="IIocResolver" />，因此可以方便地批量释放解析对象</para>
    /// <para>会调用<see cref="IDisposable.Dispose"/>方法和<see cref="IIocResolver.Release(object)"/>方法来释放对象</para>
    /// </summary>
    public class ScopedIocResolver : IScopedIocResolver
    {
        private readonly IIocResolver _iocResolver;
        private readonly List<object> _resolvedObjects;

        public ScopedIocResolver(IIocResolver iocResolver)
        {
            _iocResolver = iocResolver;
            _resolvedObjects = new List<object>();
        }

        public T Resolve<T>()
        {
            return (T)Resolve(typeof(T));
        }

        public object Resolve(Type type)
        {
            var resolvedObject = _iocResolver.Resolve(type);

            _resolvedObjects.Add(resolvedObject);
            return resolvedObject;
        }

        public T[] ResolveAll<T>()
        {
            var resolvedObjects = _iocResolver.ResolveAll<T>();

            _resolvedObjects.AddRange(resolvedObjects.OfType<object>());
            return resolvedObjects;
        }

        /// <summary>
        /// 获取给定类型的所有实现
        /// <para>返回对象必须在使用后释放，请看<see cref="Release(object)"/></para>
        /// </summary>
        /// <param name="type">要解析的对象类型</param>
        /// <returns>对象实例</returns>
        public Array ResolveAll(Type type)
        {
            return _iocResolver.ResolveAll(type);
        }

        public object Resolve(string key, Type service, Arguments arguments)
        {
            return _iocResolver.Resolve(key, service, arguments);
        }

        public T Resolve<T>(string key, Arguments arguments)
        {
            return _iocResolver.Resolve<T>(key, arguments);
        }

        public T Resolve<T>(Arguments arguments)
        {
            return _iocResolver.Resolve<T>(arguments);
        }

        public object Resolve(string key, Type service)
        {
            return _iocResolver.Resolve(key, service);
        }

        public T Resolve<T>(string key)
        {
            return _iocResolver.Resolve<T>(key);
        }

        public object Resolve(Type service, Arguments arguments)
        {
            return _iocResolver.Resolve(service, arguments);
        }

        public Array ResolveAll(Type service, Arguments arguments)
        {
            return _iocResolver.ResolveAll(service, arguments);
        }

        public T[] ResolveAll<T>(Arguments arguments)
        {
            return _iocResolver.ResolveAll<T>(arguments);
        }

        public void Release(object obj)
        {
            _resolvedObjects.Remove(obj);
            _iocResolver.Release(obj);
        }

        public bool IsRegistered(Type type)
        {
            return _iocResolver.IsRegistered(type);
        }

        public bool IsRegistered<T>()
        {
            return IsRegistered(typeof(T));
        }

        public void Dispose()
        {
            _resolvedObjects.ForEach(_iocResolver.Release);
        }
    }
}
